package com.tengju.bff.interfaces.covercharge.controller.admin;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.idanchuang.component.base.JsonResult;
import com.idanchuang.component.base.util.StringUtil;
import com.idanchuang.component.redis.util.DRedisLocks;
import com.tengju.bff.interfaces.covercharge.constant.BizConstants;
import com.tengju.bff.interfaces.covercharge.constant.CoverChargeErrorCode;
import com.tengju.bff.interfaces.covercharge.constant.PageSize;
import com.tengju.bff.interfaces.covercharge.constant.TaskStatusEnum;
import com.tengju.bff.interfaces.covercharge.entity.po.ServiceRewardPunishDetail;
import com.tengju.bff.interfaces.covercharge.entity.vo.*;
import com.tengju.bff.interfaces.covercharge.enums.ProfitTypeEnum;
import com.tengju.bff.interfaces.covercharge.service.IServiceRewardPunishDetailService;
import com.tengju.bff.interfaces.covercharge.service.ITaskService;
import com.tengju.bff.interfaces.covercharge.util.DateTimeUtils;
import com.tengju.bff.interfaces.covercharge.util.ExcelExportUtil;
import com.tengju.bff.interfaces.shared.ApiResponse;
import com.tengju.bff.interfaces.shared.servlet.ManageEntrance;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.tengju.bff.interfaces.covercharge.util.ZipUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;
import java.util.zip.ZipOutputStream;

/**
 * @Author: cj
 * @Description: 奖惩审核controller
 * @Date: 2020/12/15 16:19
 */
@Api(value = "punish/deal", tags = "Admin奖惩审核页相关")
@RestController
@Slf4j
@RequestMapping("/manage/punish/deal")
@ManageEntrance
public class AdminPunishDealController {

    @Resource
    private IServiceRewardPunishDetailService serviceRewardPunishDetailService;
    @Resource
    private ITaskService taskService;
    @Resource
    private ThreadPoolExecutor threadPoolExecutor;

    @PostMapping("/getDealInfo")
    @ApiOperation(value = "审核页条件查询/详情", notes = "审核页条件查询/详情")
    public ApiResponse<IPage<AdminPunishDealVo>> getDealInfo(@RequestBody AdminPunishDealQuery adminPunishDealQuery) {
        try {
            //校验是否有查询条件,若没有则默认创建时间为当天
            if(adminPunishDealQuery.getAgentId()==null && StringUtils.isBlank(adminPunishDealQuery.getApplyNo()) && adminPunishDealQuery.getIdCode() == null && StringUtils.isBlank(adminPunishDealQuery.getAccount()) && adminPunishDealQuery.getDealId()==null && adminPunishDealQuery.getProfitType() == null && adminPunishDealQuery.getStatus()==null){
                adminPunishDealQuery.setDoneStartTime(DateTimeFormatter.ofPattern(DateTimeUtils.DATE_FORMAT).format(LocalDateTime.now()));
                adminPunishDealQuery.setDoneEndTime(DateTimeFormatter.ofPattern(DateTimeUtils.DEFAULT_DATE_TIME_FORMAT).format(LocalDateTime.now()));
            }
            return ApiResponse.newSuccess(serviceRewardPunishDetailService.getApplyCheckList(adminPunishDealQuery));
        } catch (Exception e) {
            log.error("[违约金][审核页条件查询失败]", e);
            return ApiResponse.newFailure(CoverChargeErrorCode.SYS_ERROR.getCode(), "查询失败");
        }
    }

    @PostMapping("/batchCheckApply")
    @ApiOperation(value = "批量审核通过", notes = "批量审核通过")
    public ApiResponse<?> batchCheckApply(@RequestBody AdminPunishDealUpdate adminPunishDealUpdate) {
        Assert.isTrue((adminPunishDealUpdate != null && !CollectionUtils.isEmpty(adminPunishDealUpdate.getApplyNoList())),"申请单号不能为空");
        Assert.notNull(adminPunishDealUpdate.getDealBy(),"审核人不能为空");

        return DRedisLocks.runWithLock(BizConstants.REWARD_PUNISH_APPLY_APPROVED_ + adminPunishDealUpdate.getApplyNoList(), 500, () -> {
            try {
                //剔除重复申请单号
                adminPunishDealUpdate.setApplyNoList(serviceRewardPunishDetailService.removeDuplicate(adminPunishDealUpdate.getApplyNoList()));

                //获取总数
                Integer size=serviceRewardPunishDetailService.sumApplyNum(adminPunishDealUpdate.getApplyNoList());

                //异步处理开始
                PersonalGiveImportTaskResult taskResult = taskService.rewardCreateTask(size, "违约金批量审核通过",adminPunishDealUpdate.getDealBy());
                if (!taskResult.isTaskResult()) {
                    return ApiResponse.newFailure(CoverChargeErrorCode.SYS_ERROR.getCode(), taskResult.getErrorMsg());
                }

                //开始异步处理
                threadPoolExecutor.execute(() -> {
                    try {
                        for(String applyNo:adminPunishDealUpdate.getApplyNoList()){
                            List<ServiceRewardPunishDetail> list= serviceRewardPunishDetailService.getApplyList(applyNo);
                            for(ServiceRewardPunishDetail reward:list){
                                //缓存判断开始
                                RewardPunishRedisReturnVo rewardPunishRedisReturnVo=serviceRewardPunishDetailService.redisSet(reward.getId(),reward.getApplyNo());
                                if(!rewardPunishRedisReturnVo.getIsSet()){
                                    continue;
                                }

                                //更新处理中
                                serviceRewardPunishDetailService.updateTask(taskResult.getTaskNo(), TaskStatusEnum.DEAL.getCode(),null);

                                //开始处理
                                serviceRewardPunishDetailService.approved(taskResult.getTaskNo(),reward.getId(),adminPunishDealUpdate.getDealBy());
                            }
                        }
                    } catch (Exception e) {
                        log.error("[违约金][审核通过失败][异步线程处理异常]taskNo{},info{}",taskResult.getTaskNo(),e);
                        //更新为失败
                        serviceRewardPunishDetailService.updateTask(taskResult.getTaskNo(), TaskStatusEnum.FAIL.getCode(),"批量审核通过处理失败，执行抛异常，请看日志");
                    }
                });
                return ApiResponse.newSuccess("任务编号：" + taskResult.getTaskNo() + ",任务标识：" + taskResult.getTaskKey());
            } catch (Exception e) {
                log.error("[违约金][批量审核通过失败]", e);
                return ApiResponse.newFailure(CoverChargeErrorCode.SYS_ERROR.getCode(), "批量审核通过失败");
            }
        });
    }

    @PostMapping("/batchRejectApply")
    @ApiOperation(value = "批量驳回", notes = "批量驳回")
    public ApiResponse<?> batchRejectApply(@RequestBody AdminPunishDealUpdate adminPunishDealUpdate) {
        Assert.isTrue((adminPunishDealUpdate!= null && !CollectionUtils.isEmpty(adminPunishDealUpdate.getApplyNoList())),"申请单号不能为空");
        Assert.notNull(adminPunishDealUpdate.getDealBy(),"审核人不能为空");

        return DRedisLocks.runWithLock(BizConstants.REWARD_PUNISH_APPLY_APPROVED_ + adminPunishDealUpdate.getApplyNoList(), 500, () -> {
            try {
                //剔除重复申请单号
                adminPunishDealUpdate.setApplyNoList(serviceRewardPunishDetailService.removeDuplicate(adminPunishDealUpdate.getApplyNoList()));

                //获取总数
                Integer size=serviceRewardPunishDetailService.sumApplyNum(adminPunishDealUpdate.getApplyNoList());

                //异步处理开始
                PersonalGiveImportTaskResult taskResult = taskService.rewardCreateTask(size, "违约金批量驳回",adminPunishDealUpdate.getDealBy());
                if (!taskResult.isTaskResult()) {
                    return ApiResponse.newFailure(CoverChargeErrorCode.SYS_ERROR.getCode(), taskResult.getErrorMsg());
                }

                //开始异步处理
                threadPoolExecutor.execute(() -> {
                    try {
                        for(String applyNo:adminPunishDealUpdate.getApplyNoList()){
                            List<ServiceRewardPunishDetail> list= serviceRewardPunishDetailService.getApplyList(applyNo);
                            for(ServiceRewardPunishDetail reward:list){
                                //缓存判断开始
                                RewardPunishRedisReturnVo rewardPunishRedisReturnVo=serviceRewardPunishDetailService.redisSet(reward.getId(),reward.getApplyNo());
                                if(!rewardPunishRedisReturnVo.getIsSet()){
                                    continue;
                                }

                                //更新处理中
                                serviceRewardPunishDetailService.updateTask(taskResult.getTaskNo(), TaskStatusEnum.DEAL.getCode(),null);

                                //开始处理
                                serviceRewardPunishDetailService.rejectApply(reward.getId(),adminPunishDealUpdate.getDealBy(),taskResult.getTaskNo());
                            }
                        }
                    } catch (Exception e) {
                        log.error("[违约金][批量驳回失败][异步线程处理异常]taskNo{},info{}",taskResult.getTaskNo(),e);
                        //更新为失败
                        serviceRewardPunishDetailService.updateTask(taskResult.getTaskNo(), TaskStatusEnum.FAIL.getCode(),"批量驳回失败，执行抛异常，请看日志");
                    }
                });
                return ApiResponse.newSuccess("任务编号：" + taskResult.getTaskNo() + ",任务标识：" + taskResult.getTaskKey());
            } catch (Exception e) {
                log.error("[违约金][批量驳回失败]", e);
                return ApiResponse.newFailure(CoverChargeErrorCode.SYS_ERROR.getCode(), "批量驳回失败");
            }
        });
    }

    @PostMapping("/rejectApply")
    @ApiOperation(value = "单笔批量驳回", notes = "单笔批量驳回")
    public ApiResponse<?> rejectApply(@RequestBody AdminPunishDealUpdate adminPunishDealUpdate) {
        Assert.isTrue(adminPunishDealUpdate.getId()!=null,"记录id不能为空");
        Assert.notNull(adminPunishDealUpdate.getApplyNo(),"申请单号不能为空");
        Assert.notNull(adminPunishDealUpdate.getDealBy(),"审核人不能为空");

        return DRedisLocks.runWithLock(BizConstants.REWARD_PUNISH_APPLY_APPROVED_ + adminPunishDealUpdate.getId(), 500, () -> {
            try {
                //缓存判断开始
                RewardPunishRedisReturnVo rewardPunishRedisReturnVo=serviceRewardPunishDetailService.redisSet(adminPunishDealUpdate.getId(),adminPunishDealUpdate.getApplyNo());
                if(!rewardPunishRedisReturnVo.getIsSet()){
                    return ApiResponse.newFailure(CoverChargeErrorCode.SYS_ERROR.getCode(), rewardPunishRedisReturnVo.getMsg());
                }

                //开始处理
                serviceRewardPunishDetailService.rejectApply(adminPunishDealUpdate.getId(),adminPunishDealUpdate.getDealBy(),null);
                return ApiResponse.newSuccess();
            } catch (Exception e) {
                log.error("[违约金][单笔驳回失败]", e);
                return ApiResponse.newFailure(CoverChargeErrorCode.SYS_ERROR.getCode(), "单笔驳回失败");
            }
        });
    }

    @PostMapping("/batchRevokeApply")
    @ApiOperation(value = "批量撤销", notes = "批量撤销")
    public ApiResponse<?> batchRevokeApply(@RequestBody AdminPunishDealUpdate adminPunishDealUpdate) {
        Assert.isTrue((adminPunishDealUpdate != null && !CollectionUtils.isEmpty(adminPunishDealUpdate.getApplyNoList())),"申请单号不能为空");
        Assert.notNull(adminPunishDealUpdate.getDealBy(),"审核人不能为空");

        return DRedisLocks.runWithLock(BizConstants.REWARD_PUNISH_APPLY_APPROVED_ + adminPunishDealUpdate.getApplyNoList(), 500, () -> {
            try {
                //剔除重复申请单号
                adminPunishDealUpdate.setApplyNoList(serviceRewardPunishDetailService.removeDuplicate(adminPunishDealUpdate.getApplyNoList()));

                //获取总数
                Integer size=serviceRewardPunishDetailService.sumApplyNum(adminPunishDealUpdate.getApplyNoList());

                //异步处理开始
                PersonalGiveImportTaskResult taskResult = taskService.rewardCreateTask(size, "违约金批量撤销",adminPunishDealUpdate.getDealBy());
                if (!taskResult.isTaskResult()) {
                    return ApiResponse.newFailure(CoverChargeErrorCode.SYS_ERROR.getCode(), taskResult.getErrorMsg());
                }

                //开始异步处理
                threadPoolExecutor.execute(() -> {
                    try {
                        for(String applyNo:adminPunishDealUpdate.getApplyNoList()){
                            List<ServiceRewardPunishDetail> list= serviceRewardPunishDetailService.getApplyList(applyNo);
                            for(ServiceRewardPunishDetail reward:list){
                                //缓存判断开始
                                RewardPunishRedisReturnVo rewardPunishRedisReturnVo=serviceRewardPunishDetailService.redisSet(reward.getId(),reward.getApplyNo());
                                if(!rewardPunishRedisReturnVo.getIsSet()){
                                    continue;
                                }

                                //更新处理中
                                serviceRewardPunishDetailService.updateTask(taskResult.getTaskNo(), TaskStatusEnum.DEAL.getCode(),null);

                                //开始处理
                                serviceRewardPunishDetailService.revokeApply(reward.getId(),adminPunishDealUpdate.getDealBy(),reward.getApplyNo(),taskResult.getTaskNo());
                            }
                        }
                    } catch (Exception e) {
                        log.error("[违约金][批量撤销失败][异步线程处理异常]taskNo{},info{}",taskResult.getTaskNo(),e);
                        //更新为失败
                        serviceRewardPunishDetailService.updateTask(taskResult.getTaskNo(), TaskStatusEnum.FAIL.getCode(),"批量撤销失败，执行抛异常，请看日志");
                    }
                });
                return ApiResponse.newSuccess("任务编号：" + taskResult.getTaskNo() + ",任务标识：" + taskResult.getTaskKey());
            } catch (Exception e) {
                log.error("[违约金][批量撤销失败]", e);
                return ApiResponse.newFailure(CoverChargeErrorCode.SYS_ERROR.getCode(), "批量撤销失败");
            }
        });
    }

    @PostMapping("/revokeApply")
    @ApiOperation(value = "单笔撤销", notes = "单笔撤销")
    public ApiResponse<?> revokeApply(@RequestBody AdminPunishDealUpdate adminPunishDealUpdate) {
        Assert.isTrue(adminPunishDealUpdate.getId()!=null,"记录id不能为空");
        Assert.notNull(adminPunishDealUpdate.getApplyNo(),"申请单号不能为空");
        Assert.notNull(adminPunishDealUpdate.getDealBy(),"审核人不能为空");

        return DRedisLocks.runWithLock(BizConstants.REWARD_PUNISH_APPLY_APPROVED_ + adminPunishDealUpdate.getId(), 500, () -> {
            try {
                //缓存判断开始
                RewardPunishRedisReturnVo rewardPunishRedisReturnVo=serviceRewardPunishDetailService.redisSet(adminPunishDealUpdate.getId(),adminPunishDealUpdate.getApplyNo());
                if(!rewardPunishRedisReturnVo.getIsSet()){
                    return ApiResponse.newFailure(CoverChargeErrorCode.SYS_ERROR.getCode(), rewardPunishRedisReturnVo.getMsg());
                }

                //开始处理
                serviceRewardPunishDetailService.revokeApply(adminPunishDealUpdate.getId(),adminPunishDealUpdate.getDealBy(),adminPunishDealUpdate.getApplyNo(),null);
                return ApiResponse.newSuccess();
            } catch (Exception e) {
                log.error("[违约金][单笔撤销失败]", e);
                return ApiResponse.newFailure(CoverChargeErrorCode.SYS_ERROR.getCode(), "单笔撤销失败");
            }
        });
    }

    @PostMapping("/exportInfo")
    @ApiOperation(value = "导出", notes = "导出")
    public void exportInfo(AdminPunishDealQuery adminPunishDealQuery, HttpServletRequest request, HttpServletResponse response) {
        try {
            //获取总数
            long count=serviceRewardPunishDetailService.getApplyCheckTotal(adminPunishDealQuery);

            //定义多个excel
            List<Workbook> workbookList = new ArrayList<>();

            if(count!=0){
                Integer page=serviceRewardPunishDetailService.getPage(count);
                //循环遍历,分页查询
                for (int i = 1; i <= page; i++) {
                    adminPunishDealQuery.setCurrent(i);
                    adminPunishDealQuery.setSize(PageSize.REWARD_EXPORT_PAGE_SIZE);
                    IPage<AdminPunishDealVo> punishDealVoPage=serviceRewardPunishDetailService.getApplyCheckList(adminPunishDealQuery);

                    log.info("[财务管理后台][导出奖惩申请发放列表][导出用户:{}]",adminPunishDealQuery);
                    ExcelExportUtil excel = new ExcelExportUtil();
                    excel.createRow(0);
                    excel.setCell(0, "申请单号");
                    excel.setCell(1, "用户ID");
                    excel.setCell(2, "注册号码");
                    excel.setCell(3, "代理名称");
                    excel.setCell(4, "等级");
                    excel.setCell(5, "用户身份");
                    excel.setCell(6, "处理类型");
                    excel.setCell(7, "内容");
                    excel.setCell(8, "金额");
                    excel.setCell(9, "平台");
                    excel.setCell(10, "完成时间");
                    excel.setCell(11, "审核前账户金额");
                    excel.setCell(12, "审核后账户金额");
                    excel.setCell(13, "单据类型");
                    excel.setCell(14, "备注");
                    int index = 1;

                    for (AdminPunishDealVo adminPunishDealVo : punishDealVoPage.getRecords()) {
                        excel.createRow(index);
                        excel.setCell(0, adminPunishDealVo.getApplyNo());
                        excel.setCell(1, adminPunishDealVo.getIdCode() + "");
                        //获取用户注册手机号
                        excel.setCell(2, StringUtil.isBlank(adminPunishDealVo.getRegisterMobile()) ? "" : adminPunishDealVo.getRegisterMobile());
                        excel.setCell(3, StringUtil.isBlank(adminPunishDealVo.getName()) ? "" : adminPunishDealVo.getName());
                        excel.setCell(4, StringUtil.isBlank(adminPunishDealVo.getLevel()) ? "" : adminPunishDealVo.getLevel());
                        excel.setCell(5, StringUtil.isBlank(adminPunishDealVo.getRole()) ? "" : adminPunishDealVo.getRole());
                        excel.setCell(6, StringUtil.isBlank(adminPunishDealVo.getDealValue()) ? "" : adminPunishDealVo.getDealValue());
                        excel.setCell(7, StringUtil.isBlank(adminPunishDealVo.getViolateValue()) ? "" : adminPunishDealVo.getViolateValue());
                        excel.setCell(8, adminPunishDealVo.getMoney() + "");
                        excel.setCell(9, adminPunishDealVo.getCreatedTime());
                        excel.setCell(10, StringUtil.isBlank(adminPunishDealVo.getDoneTime()) ? "" : adminPunishDealVo.getDoneTime());
                        excel.setCell(11, adminPunishDealVo.getBeforeMoney()==null ? "" : adminPunishDealVo.getBeforeMoney().toString());
                        excel.setCell(12, adminPunishDealVo.getLastMoney()==null?"":adminPunishDealVo.getLastMoney().toString());
                        String danStr;
                        if(adminPunishDealVo.getProfitType()==null){
                            danStr="";
                        }else{
                            if(ProfitTypeEnum.rewards_pt_out.getCode().equals(adminPunishDealVo.getProfitType())){
                                danStr="扣费单";
                            }else{
                                danStr="入账单";
                            }
                        }
                        excel.setCell(13, danStr);
                        excel.setCell(14, StringUtil.isBlank(adminPunishDealVo.getRemark()) ? "" : adminPunishDealVo.getRemark());
                        index++;
                    }
                    workbookList.add(excel.getWorkbook());
                }
            }

            //获取当前时间
            String zipName = "奖惩审核_"+DateTimeFormatter.ofPattern("yyyy-MM-dd").format(LocalDateTime.now()) + ".zip";
            response.setContentType("APPLICATION/OCTET-STREAM");
            response.setHeader("Content-Disposition","attachment; filename="+zipName);
            //文件流导出
            ZipOutputStream out = null;
            try {
                out = new ZipOutputStream(response.getOutputStream());
            } catch (IOException e) {
                log.error("[违约金][审核页面导出][zip压缩导出出现错误]", e);
            }

            try {
                int zipIndex = 1;
                for (Workbook workbook : workbookList) {
                    ZipUtils.doZip(zipIndex + ".xls", workbook, out, "");
                    response.flushBuffer();
                    zipIndex += 1;
                }
            } catch (Exception e) {
                log.error("[违约金][审核页面导出][zip压缩导出出现错误]", e);
            }finally{
                if(out!=null){
                    try {
                        out.close();
                    } catch (IOException iOException) {
                        log.error("[违约金][审核页面导出][zip压缩关闭流出现错误]", iOException);
                    }
                }
            }
        } catch (Exception e) {
            log.error("[违约金][审核页面导出][失败信息]", e);
        }
    }
}
